#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include "Thread.hpp"
#include "Task.hpp"
#include "LockGuard.hpp"
#include "log.hpp"


const static int N = 20;

template <class T>
class ThreadPool{
private:
    ThreadPool(int num = N)
    : _num(num){
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool<T> &tp) = delete;
    void operator = (const ThreadPool<T> &tp) = delete;

public:

    static ThreadPool<T> *getInstance(){
        if(nullptr == instance){
            LockGuard lockGuard(&instanceLock);
            if(nullptr == instance){
                logMessage(Debug, "线程池单例形成");
                instance = new ThreadPool<T>();
                instance->init();
                instance->start();
            }
        }
        return instance;
    }
    
    pthread_mutex_t* getLock(){
        return &_lock;
    }

    void threadWait(){
        pthread_cond_wait(&_cond, &_lock);
    }

    void threadWackup(){
        pthread_cond_signal(&_cond);
    }

    bool isEmpty(){
        return _tasks.empty();
    }

    T popTask(){
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    static void threadRoutine(void *args){
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *> (args);
        while(true){
            T t;
            {   
                LockGuard lock(tp->getLock());
                while(tp->isEmpty()){
                    tp->threadWait();
                }
                t = tp->popTask();
            }
            tp->runTask(t);
        }
    }

    void init(){
        for(int i = 0; i < _num; i++){
            _threads.push_back(Thread(i, threadRoutine, this));
            logMessage(Debug, "%d thread running", i);
        }
    }

    void start(){
        for(auto &t : _threads)
            t.run();
    }

    void check(){
        for(auto &t : _threads)
            cout << t.threadName()  << " " << t.threadId() << " " << "running" << endl;
    }

    void runTask(T t){
        t();
        //cout << pthread_self() << " | consumer data: " << t.formatArg() << t.formatRes() << endl;
    }

    void pushTask(const T& t){
        LockGuard lock(&_lock);
        _tasks.push(t);
        threadWackup();//push完任务后将排队等待的线程唤醒
    }

    ~ThreadPool(){
        for(auto &t : _threads)
            t.join();
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    vector<Thread> _threads;
    int _num;
    queue<T> _tasks;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;

    static ThreadPool<T> *instance;
    static pthread_mutex_t instanceLock;
};

template <class T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::instanceLock = PTHREAD_MUTEX_INITIALIZER;